package com.sz.biz.common.contract.service.impl;

import com.google.common.collect.Lists;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.common.constants.ModuleNames;
import com.sz.biz.common.contract.dto.*;
import com.sz.biz.common.contract.entity.ContTemplate;
import com.sz.biz.common.contract.service.ContTypeEnum;
import com.sz.biz.common.contract.service.ServiceTypeEnum;
import com.sz.biz.common.contract.service.ContContractorService;
import com.sz.biz.common.contract.service.ContFieldService;
import com.sz.biz.common.contract.service.ContTemplateService;
import com.sz.common.base.constants.UserActions;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.EntityUtils;
import com.sz.biz.logistics.constants.ErrorCodes;
import com.sz.common.core.service.PrincipalLogUtils;
import com.sz.common.core.service.PrincipalUtils;
import com.sz.common.core.system.service.SysUserSupport;
import com.sz.common.core.system.service.UserModel;
import com.sz.common.core.system.dto.SimpleUserDto;
import com.sz.common.core.system.entity.User;
import com.sz.common.core.system.service.UserService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Package: com.sz.biz.common.contract.service.impl<br>
 * Function: 合同模板serviceImpl
 * Author: yanhong.xiao.<br>
 * Date: 2017-07-19 16:07:00.
 */
@Service
public class ContTemplateServiceImpl extends AbstractService implements ContTemplateService {

    @Autowired
    private ContContractorService contContractorService;
    @Autowired
    private ContFieldService contFieldService;
    @Autowired
    private SysUserSupport sysUserSupport;
    @Autowired
    private UserService userService;
    @Override
    protected String getMapperNamespace() {
        return "com.sz.biz.common.contract.entity.ContTemplateMapper";
    }

    /**
     * 保存合同模板业务
     * 1.保存模板
     * 2. 保存合同方
     * 3.保存field
     *
     * @param templateDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ContTemplate saveTemplate(ContTemplateDto templateDto) {
        ContTemplate template = new ContTemplate();
        if (null != templateDto) {
            //参数校验
            validateTemplateDto(templateDto);
            EntityUtils.copyPropertiesIgnoreNull(templateDto, template);
            template.setId(null);
            template.setCreateUserId(PrincipalUtils.getAccountId());
            template.setLastUpdateUserId(PrincipalUtils.getAccountId());
            //1.保存合同模板
            dao.save(getSqlName("insertSelective"), template);
            //2.保存合同方
            List<ContContractorDto> contContractorDtoList = getContractorDtoList(templateDto, template.getId());
            contContractorService.batchSave(contContractorDtoList);
            //保存field
            List<ContFieldDto> fieldDtoList = getFieldDtoList(templateDto, template.getId());
            contFieldService.batchSave(fieldDtoList);
            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("ADD_CONT_TEMPLATE", templateDto);
            PrincipalLogUtils.addOperationLog(ModuleNames.CONT, ModuleNames.CONT_TEMPLATE, UserActions.ADD, "新增合同模板", dataBackup);
        }

        return template;
    }

    /**
     * 修改合同模板
     * 1.判断该合同模板是否存在，
     * 2.判断该合同模板是否为当前用户的合同的模板
     * 3.检验,模板名称不可以修改
     * 3.进行修改
     * 3.1 处理合同方,删除原来合同方，增加新的合同方
     * 3.2 处理field，删除原来field，增加新的field
     * 3.3 修改合同模板
     *
     * @param templateDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContTemplate updateTemplate(ContTemplateDto templateDto) {
        // 1.判断该合同模板是否存在，
        if (null == templateDto  || templateDto.getId() <= 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NOT_EXISTS);
        }
        ContTemplate oldTemplate = getById(templateDto.getId());
        if (null == oldTemplate) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NOT_EXISTS);
        }
        //2.判断该合同模板是否为当前用户的合同的模板
        if (oldTemplate.getCreateUserId().intValue() != PrincipalUtils.getAccountId()) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NO_AUTH);
        }
        //检验合同模板的名称不能修改
        if (!oldTemplate.getName().equals(templateDto.getName())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NAME_CAN_NOT_UPDATE);
        }
        validateTemplateDto(templateDto);
        // 3.进行修改
        // 3.1 处理合同方,删除原来合同方，增加新的合同方
        List<Integer> relIds = Lists.newArrayList();
        relIds.add(templateDto.getId());
        contContractorService.batchDeleteByRelIds(ContTypeEnum.CONT_TEMPLATE, relIds);
        List<ContContractorDto> contContractorDtoList = getContractorDtoList(templateDto, templateDto.getId());
        contContractorService.batchSave(contContractorDtoList);
        //3.2 处理field，删除原来field，增加新的field
        contFieldService.batchDeleteByRelIds(ContTypeEnum.CONT_TEMPLATE, relIds);
        List<ContFieldDto> fieldDtoList = getFieldDtoList(templateDto, templateDto.getId());
        contFieldService.batchSave(fieldDtoList);
        ContTemplate newTemplate = new ContTemplate();
        EntityUtils.copyPropertiesIgnoreNull(templateDto, newTemplate);
        newTemplate.setType(oldTemplate.getType());
        newTemplate.setIsDeleted(oldTemplate.getIsDeleted());
        //3.3 修改合同模板
        dao.update(getSqlName("updateNull"), newTemplate);
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_CONT_TEMPLATE", templateDto);
        PrincipalLogUtils.addOperationLog(ModuleNames.CONT, ModuleNames.CONT_TEMPLATE, UserActions.UPDATE, "需改合同模板", dataBackup);
        return newTemplate;
    }

    @Override
    public ContTemplate getById(Integer id) {
        ContTemplate template = (ContTemplate) dao.findForObject(getSqlName("getById"), id);
        return template;
    }

    /**
     * 获取合同模板dto
     * //获取template基本信息
     * //处理创建人姓名
     * //处理合同方
     * //处理field
     *
     * @param id
     * @return
     */
    @Override
    public ContTemplateDto getDtoById(Integer id) {
        ContTemplateDto dto = null;
        if (null != id) {
            ContTemplate template = getById(id);
            if (null == template) {
                return dto;
            } else {
                dto = new ContTemplateDto();
                //获取template基本信息
                EntityUtils.copyPropertiesIgnoreNull(template, dto);
                //处理创建人姓名
                UserModel userModel = sysUserSupport.getUserById(template.getCreateUserId());
                dto.setCreateUserName(userModel.getAccountName());
                dto.setServiceTypeName(ServiceTypeEnum.valueOfEnum(String.valueOf(template.getServiceType())).getName());
                //处理合同方
                Map<String, ContContractorDto> map = contContractorService.getContractorDtosByRelId(ContTypeEnum.CONT_TEMPLATE, id);
                ContContractorDto first = map.get(CommCodes.CONT_CONTRACTOR_FIRST_KEY);
                if (null != first) {
                    dto.setFirstContractorDto(first);
                }
                ContContractorDto second = map.get(CommCodes.CONT_CONTRACTOR_SECOND_KEY);
                if (null != second) {
                    dto.setSecondContractorDto(second);
                }
                //处理field
                Map<String, String> contFields = contFieldService.getFields(ContTypeEnum.CONT_TEMPLATE, id);
                if (null != contFields) {
                    dto.setTitle(contFields.get(CommCodes.CONT_FIELD_TITLE_KEY));
                    dto.setContent(contFields.get(CommCodes.CONT_FIELD_CONTENT_KEY));
                }
                return dto;
            }
        }
        return dto;
    }


    @Override
    public ResultDto findSimpleDtoPages(QueryParams params) {
        List<ContTemplateSimpleDto> dtoData = Lists.newArrayList();
        List<SimpleUserDto> users = Lists.newArrayList();
        List<Integer> createUserIds = Lists.newArrayList();
        Map<String, Object> selectParams = params.getParam();
        if (null != selectParams) {
            String createUserName = (String) selectParams.get("createUserName");
            if (StringUtils.isNotBlank(createUserName)) {
                ResultDto userResult = userService.findByCodeLike(createUserName.trim());
                if (null != userResult && null != userResult.getData()) {
                    users = (List<SimpleUserDto>) userResult.getData();
                    users.forEach(simpleUserDto -> {
                        createUserIds.add(simpleUserDto.getId());
                    });
                }
                if (CommCodes.ROOT_ACCOUNT.indexOf(createUserName)>=0){
                    createUserIds.add(1);
                }
                if (!CollectionUtils.isEmpty(createUserIds)) {
                    params.put("createUserIds", createUserIds);
                } else {
                    ParamData pd = convertQueryParams(params);
                    //没有此用户，直接返回空数据
                    return new QResultDto(dtoData, pd.getPagination());
                }
            }
        }
        ParamData pd = convertQueryParams(params);
        //1、根据条件查询
        List<ContTemplate> templateList = dao.findForList(getSqlName("findListPage"), pd, ContTemplate.class);
        if (CollectionUtils.isNotEmpty(templateList)) {
            //拼装数据
            List<Integer> templateIds = Lists.newArrayList();
            templateList.forEach(template -> {
                templateIds.add(template.getId());
                createUserIds.add(template.getCreateUserId());
            });

            // 创建人的姓名
            Map<Object, SimpleUserDto> userMap = new HashedMap();
            if (CollectionUtils.isNotEmpty(users)) {
                //表示创建人都在这个集合中
                users.forEach(simpleUserDto -> {
                    userMap.put(simpleUserDto.getId(), simpleUserDto);
                });
            } else {
                //需要自己去查询一次
                List<User> createUsers = userService.findByIds(createUserIds);
                createUsers.forEach(user -> {
                    SimpleUserDto simpleUserDto = new SimpleUserDto();
                    EntityUtils.copyPropertiesIgnoreNull(user, simpleUserDto);
                    userMap.put(simpleUserDto.getId(), simpleUserDto);
                });
            }
            templateList.forEach(template -> {
                ContTemplateSimpleDto dto = new ContTemplateSimpleDto();
                EntityUtils.copyPropertiesIgnoreNull(template, dto);
                //处理创建人姓名
                dto.setCreateUserName(userMap.get(dto.getCreateUserId()).getCode());
                //处理业务类型名称
                dto.setServiceTypeName(ServiceTypeEnum.valueOfEnum(String.valueOf(template.getServiceType())).getName());
                dtoData.add(dto);
            });
        }
        return new QResultDto(dtoData, pd.getPagination());
    }



    @Override
    public void batchDeleteByIds(List<Integer> ids) {
        if (CollectionUtils.isNotEmpty(ids)) {
            int createUserId = PrincipalUtils.getAccountId();
            Map<String, Object> map = new HashedMap();
            map.put("createUserId", createUserId);
            map.put("ids", ids);
            dao.update(getSqlName("batchUpdateIsDelete"), map);

        }
    }

    @Override
    public List<ContTemplate> getLikeByName(String name) {
        return dao.findForList(getSqlName("getLikeByName"), name, ContTemplate.class);
    }

    @Override
    public List<ContTemplate> getByIds(List<Integer> ids) {
        Map<String, Object> map = new HashedMap();
        map.put("ids", ids);
        return dao.findForList(getSqlName("getByIds"), map, ContTemplate.class);
    }

    @Override
    public ResultDto findMinDtoPages(QueryParams params) {
        List<ContTemplateMinDto> dtos = Lists.newArrayList();
        //1、根据条件查询
        ParamData pd = convertQueryParams(params);
        List<ContTemplate> templateList = dao.findForList(getSqlName("findListPage"), pd, ContTemplate.class);
        if (CollectionUtils.isNotEmpty(templateList)) {
            templateList.forEach(template -> {
                ContTemplateMinDto minDto = new ContTemplateMinDto();
                minDto.setId(template.getId());
                minDto.setName(template.getName());
                dtos.add(minDto);
            });
        }

        return new QResultDto(dtos, pd.getPagination());
    }

    @Override
    public boolean checkUniqueName(Integer id, String name) {
        //根据name去查询模板
        List<ContTemplate> templateList = dao.findForList(getSqlName("getByName"), name, ContTemplate.class);
        if (CollectionUtils.isNotEmpty(templateList)) {
            if (null == id) {
                //新增校验,已经存在
                return true;
            } else {
                if (templateList.get(0).getId().intValue() != id.intValue()) {
                    //说明存在
                    return true;
                }
            }
        }
        //不存在
        return false;
    }


    private List<ContFieldDto> getFieldDtoList(ContTemplateDto templateDto, Integer templateId) {
        List<ContFieldDto> fieldDtoList = Lists.newArrayList();
        ContFieldDto titleDto = new ContFieldDto();
        titleDto.setType(ContTypeEnum.getIntegerCode(ContTypeEnum.CONT_TEMPLATE));
        titleDto.setRelId(templateId);
        titleDto.setFieldKey(CommCodes.CONT_FIELD_TITLE_KEY);
        titleDto.setFieldValue(templateDto.getTitle());
        titleDto.setOrderNum(1);
        fieldDtoList.add(titleDto);

        ContFieldDto contentDto = new ContFieldDto();
        contentDto.setType(ContTypeEnum.getIntegerCode(ContTypeEnum.CONT_TEMPLATE));
        contentDto.setRelId(templateId);
        contentDto.setFieldKey(CommCodes.CONT_FIELD_CONTENT_KEY);
        contentDto.setFieldValue(templateDto.getContent());
        contentDto.setOrderNum(2);
        fieldDtoList.add(contentDto);


        return fieldDtoList;
    }


    /**
     * 处理甲方，乙方数据
     *
     * @param templateDto
     * @param templateId
     * @return
     */
    private List<ContContractorDto> getContractorDtoList(ContTemplateDto templateDto, Integer templateId) {
        //甲方
        ContContractorDto firstContractorDto = templateDto.getFirstContractorDto();
        firstContractorDto.setType(Integer.valueOf(ContTypeEnum.CONT_TEMPLATE.getCode()));
        firstContractorDto.setContractorType(CommCodes.CONT_CONTRACTOR_FIRST);
        firstContractorDto.setRelId(templateId);
        //乙方
        ContContractorDto secondContractorDto = templateDto.getSecondContractorDto();
        secondContractorDto.setType(Integer.valueOf(ContTypeEnum.CONT_TEMPLATE.getCode()));
        secondContractorDto.setContractorType(CommCodes.CONT_CONTRACTOR_SECOND);
        secondContractorDto.setRelId(templateId);
        List<ContContractorDto> contContractorDtoList = Lists.newArrayList();
        contContractorDtoList.add(firstContractorDto);
        contContractorDtoList.add(secondContractorDto);
        return contContractorDtoList;

    }

    public boolean validateTemplateDto(ContTemplateDto templateDto) {
        //必填项目的校验
        if (StringUtils.isBlank(templateDto.getName())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NAME_NOT_NULL);
        }
        if (StringUtils.isBlank(templateDto.getTitle())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_TITLE_NOT_NULL);
        }
        if (null == ServiceTypeEnum.valueOfEnum(String.valueOf(templateDto.getServiceType()))) {
            throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_SERVICETYPE_NOT_NULL);
        }
        if (null == templateDto.getId() || templateDto.getId()<=0) {
            //新增
            if (checkUniqueName(null, templateDto.getName())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NAME_EXISTS);
            }
        } else {
            //修改
            if (checkUniqueName(templateDto.getId(), templateDto.getName())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_NAME_EXISTS);
            }
        }
        //检查content的html安全
        if (StringUtils.isNotBlank(templateDto.getContent())) {
            if (HtmlUtils.validateHtml(templateDto.getContent())) {
                //有非法字符
                throw Exceptions.bizException(ErrorCodes.ERROR_CONT_TEMPLATE_CONTENT_INVALID);
            }
        }
        return true;
    }
}
